[Chapter Thirteen][Previous]
[Next] [Art of
Assembly][Randall Hyde]
Art of Assembly: Chapter Thirteen
- 13.3.6 - MS-DOS Memory Management Functions
- 13.3.6.1 - Allocate Memory
- 13.3.6.2 - Deallocate Memory
- 13.3.6.3 - Modify Memory Allocation
- 13.3.6.4 - Advanced Memory Management
Functions
- 13.3.7 - MS-DOS Process Control Functions
- 13.3.7.1 - Terminate Program Execution
- 13.3.7.2 - Terminate, but Stay Resident
- 13.3.7.3 - Execute a Program
13.3.6 MS-DOS Memory Management Functions
MS-DOS provides three memory management functions- allocate, deallocate,
and resize (modify). For most programs, these three memory allocation calls
are not used. When DOS executes a program, it gives all of the available
memory, from the start of that program to the end of RAM, to the executing
process. Any attempt to allocate memory without first giving unused memory
back to the system will produce an "insufficient memory" error.
Sophisticated programs which terminate and remain resident, run other programs,
or perform complex memory management tasks, may require the use of these
memory management functions. Generally these types of programs immediately
deallocate all of the memory that they don't use and then begin allocating
and deallocating storage as they see fit.
Since these are complex functions, they shouldn't be used unless you have
a very specific purpose for them. Misusing these commands may result in
loss of system memory that can be reclaimed only by rebooting the system.
Each of the following calls returns the error status in the carry flag.
If the carry is clear on return, then the operation was completed successfully.
If the carry flag is set when DOS returns, then the ax
register
contains one of the following error codes:
7- Memory control blocks destroyed
8- Insufficient memory
9- Invalid memory block address
Additional notes about these errors will be discussed as appropriate.
13.3.6.1 Allocate Memory
Function (ah): 48h
Entry parameters: bx- Requested block size (in paragraphs)
Exit parameters: If no error (carry clear):
ax:0 points at allocated memory block
If an error (carry set):
bx- maximum possible allocation size
ax- error code (7 or 8)
This call is used to allocate a block of memory. On entry into DOS, bx
contains the size of the requested block in paragraphs (groups of
16 bytes). On exit, assuming no error, the ax
register contains
the segment address of the start of the allocated block. If an error occurs,
the block is not allocated and the ax
register is returned
containing the error code. If the allocation request failed due to insufficient
memory, the bx
register is returned containing the maximum
number of paragraphs actually available.
13.3.6.2 Deallocate Memory
Function (ah): 49h
Entry parameters: es:0- Segment address of block to be deallocated
Exit parameters: If the carry is set, ax contains the error code (7,9)
This call is used to deallocate memory allocated via function 48h above.
The es
register cannot contain an arbitrary memory address.
It must contain a value returned by the allocate memory function. You cannot
use this call to deallocate a portion of an allocated block. The modify
allocation function is used for that operation.
13.3.6.3 Modify Memory Allocation
Function (ah): 4Ah
Entry parameters: es:0- address of block to modify allocation size
bx- size of new block
Exit parameters: If the carry is set, then
ax contains the error code 7, 8, or 9
bx contains the maximum size possible (if error 8)
This call is used to change the size of an allocated block. On entry, es
must contain the segment address of the allocated block returned
by the memory allocation function. Bx
must contain the new
size of this block in paragraphs. While you can almost always reduce the
size of a block, you cannot normally increase the size of a block if other
blocks have been allocated after the block being modified. Keep this in
mind when using this function.
13.3.6.4 Advanced Memory Management Functions
The MS-DOS 58h opcode lets programmers adjust MS-DOS' memory allocation
strategy and control the use of upper memory blocks (UMBs). There are four
subfunctions to this call, with the subfunction value appearing in the al
register. The following table describes these calls:
Advanced Memory Management Functions
Function #
(AH) | Input
Parameters | Output
Parameters | Description |
---|
58h | al -0 | ax - strategy | Get Allocation Strategy: Returns the current allocation strategy in ax (see table below for details). |
58h | al-1
bx - strategy | - | Set Allocation Strategy: Sets the MS-DOS allocation strategy to the value specified in bx (see the table below for details). |
58H | al - 2 | al - link flag | Get Upper Memory Link: Returns true/false (1/0) in al to determine whether a program can allocate memory in the upper memory blocks. |
58h | al- 3
bx - link flag (0=no link, 1=link okay). | - | Set Upper Memory Link: Links or unlinks the upper memory area. When linked, an application can allocate memory from the UMB (using the normal DOS allocate call). |
Memory Allocation Strategies
Value | Name | Description |
---|
0 | First Fit Low | Search conventional memory for the first free block of memory large enough to satisfy the allocation request. This is the default case. |
1 | Best Fit Low | Search conventional memory for the smallest block large enough to satisfy the request. |
2 | Last Fit Low | Search conventional memory from the highest address downward for the first block large enough to satisfy the request. |
80h | First Fit High | Search high memory, then conventional memory, for the first available block that can satisfy the allocation request. |
81h | Best Fit High | Search high memory, then conventional memory for the smallest block large enough to satisfy the allocation request. |
82h | Last Fit High | Search high memory from high addresses to low, then conventional memory from high addresses to low, for the first block large enough to satisfy the request. |
40h | First Fit Highonly | Search high memory only for the first block large enough to satisfy the request. |
41h | Best Fit Highonly | Search high memory only for the smallest block large enough to satisfy the request. |
42h | Last Fit Highonly | Search high memory only, from the end of memory downward, for the first block large enough to satisfy the request. |
These different allocation strategies can have an impact on system performance.
For an analysis of different memory management strategies, please consult
a good operating systems theory text.
13.3.7 MS-DOS Process Control Functions
DOS provides several services dealing with loading, executing, and terminating
programs. Many of these functions have been rendered obsolete by later versions
of DOS. There are three[5] functions of general
interest- program termination, terminate and stay resident, and execute
a program. These three functions will be discussed in the following sections.
13.3.7.1 Terminate Program Execution
Function (ah): 4Ch
Entry parameters: al- return code
Exit parameters: Does not return to your program
This is the function call normally used to terminate your program. It returns
control to the calling process (normally, but not necessarily, DOS). A return
code can be passed to the calling process in the al
register.
Exactly what meaning this return code has is entirely up to you. This return
code can be tested with the DOS "IF ERRORLEVEL return code" command
in a DOS batch file. All files opened by the current process will be automatically
closed upon program termination.
Note that the UCR Standard Library function "ExitPgm
"
is simply a macro which makes this particular DOS call. This is the normal
way of returning control back to MS-DOS or some other program which ran
the currently active application.
13.3.7.2 Terminate, but Stay Resident
Function (ah): 31h
Entry parameters: al- return code
dx- memory size, in paragraphs
Exit parameters: does not return to your program
This function also terminates program execution, but upon returning to DOS,
the memory in use by the process is not returned to the DOS free memory
pool. Essentially, the program remains in memory. Programs which remain
resident in memory after returning to DOS are often called TSRs (terminate
and stay resident programs).
When this command is executed, the dx
register contains the
number of memory paragraphs to leave around in memory. This value is measured
from the beginning of the "program segment prefix", a segment
marking the start of your file in memory. The address of the PSP (program
segment prefix) is passed to your program in the ds
register
when your program is first executed. You'll have to save this value if your
program is a TSR[6].
Programs that terminate and stay resident need to provide some mechanism
for restarting. Once they return to DOS they cannot normally be restarted.
Most TSRs patch into one of the interrupt vectors (such as a keyboard, printer,
or serial interrupt vector) in order to restart whenever some hardware related
event occurs (such as when a key is pressed). This is how "pop-up"
programs like SmartKey work.
Generally, TSR programs are pop-ups or special device drivers. The TSR mechanism
provides a convenient way for you to load your own routines to replace or
augment BIOS' routines. Your program loads into memory, patches the appropriate
interrupt vector so that it points at an interrupt handler internal to your
code, and then terminates and stays resident. Now, when the appropriate
interrupt instruction is executed, your code will be called rather than
BIOS'.
There are far too many details concerning TSRs including compatibility issues,
DOS re-entrancy issues, and how interrupts are processed, to be considered
here. Additional details will appear in a later chapter.
13.3.7.3 Execute a Program
Function (ah): 40h
Entry parameters: ds:dx- pointer to pathname of program to execute
es:bx- Pointer to parameter block
al- 0=load and execute, 1=load only, 3=load overlay.
Exit parameters: If carry is set, ax contains one of the following error codes:
1- invalid function
2- file not found
5- access denied
8- not enough memory
10- bad environment
11- bad format
The execute (exec
) function is an extremely complex, but at
the same time, very useful operation. This command allows you to load or
load and execute a program off of the disk drive. On entry into the exec
function, the ds:dx
registers contain a pointer to a
zero terminated string containing the name of the file to be loaded or executed,
es:bx
points at a parameter block, and al
contains
zero or one depending upon whether you want to load and execute a program
or simply load it into memory. On return, if the carry is clear, then DOS
properly executed the command. If the carry flag is set, then DOS encountered
an error while executing the command.
The filename parameter can be a full pathname including drive and subdirectory
information. "B:\DIR1\DIR2\MYPGM.EXE" is a perfectly valid filename
(remember, however, it must be zero terminated). The segmented address of
this pathname is passed in the ds:dx
registers.
The es:bx
registers point at a parameter block for the exec
call. This parameter block takes on three different forms depending
upon whether a program is being loaded and executed (al
=0),
just loaded into memory (al
=1), or loaded as an overlay (al
=3).
If al
=0, the exec
call loads and executes a program.
In this case the es:bx
registers point at a parameter block
containing the following values:
Offset Description
0 A word value containing the segment address of the default environment
(usually this is set to zero which implies the use of the standard DOS
environment).
2 Double word pointer containing the segment address of a command line string.
6 Double word pointer to default FCB at address 5Ch
0Ah Double word pointer to default FCB at address 6Ch
The environment area is a set of strings containing default pathnames and
other information (this information is provided by DOS using the PATH, SET,
and other DOS commands). If this parameter entry contains zero, then exec
will pass the standard DOS environment on to the new procedure. If
non-zero, then this parameter contains the segment address of the environment
block that your process is passing on to the program about to be executed.
Generally, you should store a zero at this address.
The pointer to the command string should contain the segmented address of
a length prefixed string which is also terminated by a carriage return character
(the carriage return character is not figured into the length of the string).
This string corresponds to the data that is normally typed after the program
name on the DOS command line. For example, if you're executing the linker
automatically, you might pass a command string of the following form:
CmdStr byte 16,"MyPgm+Routines /m",0dh
The second item in the parameter block must contain the segmented address
of this string.
The third and fourth items in the parameter block point at the default FCBs.
FCBs are used by the obsolete DOS filing commands, so they are rarely used
in modern application programs. Since the data structures these two pointers
point at are rarely used, you can point them at a group of 20 zeros.
Example: Format a floppy disk in drive A: using the FORMAT.EXE command
mov ah, 4Bh
mov al, 0
mov dx, seg PathName
mov ds, dx
lea dx, PathName
mov bx, seg ParmBlock
mov es, bx
lea bx, ParmBlock
int 21h
.
.
.
PathName byte 'C:\DOS\FORMAT.EXE',0
ParmBlock word 0 ;Default environment
dword CmdLine ;Command line string
dword Dummy,Dummy ;Dummy FCBs
CmdLine byte 3,' A:',0dh
Dummy byte 20 dup (?)
MS-DOS versions earlier than 3.0 do not preserve any registers except cs:ip
when you execute the exec call. In particular, ss:sp is not preserved. If
you're using DOS v2.x or earlier, you'll need to use the following code:
;Example: Format a floppy disk in drive A: using the FORMAT.EXE command
<push any registers you need preserved>
mov cs:SS_Save, ss ;Save SS:SP to a location
mov cs:SP_Save, sp ; we have access to later.
mov ah, 4Bh ;EXEC DOS opcode.
mov al, 0 ;Load and execute.
mov dx, seg PathName ;Get filename into DS:DX.
mov ds, dx
lea dx, PathName
mov bx, seg ParmBlock ;Point ES:BX at parameter
mov es, bx ; block.
lea bx, ParmBlock
int 21h
mov ss, cs:SS_Save ;Restore SS:SP from saved
mov sp, cs:SP_Save ; locations.
<Restore registers pushed onto the stack>
.
.
.
SS_Save word ?
SP_Save word ?
.
.
.
PathName byte 'C:\DOS\FORMAT.EXE',0
ParmBlock word 0 ;Default environment
dword CmdLine ;Command line string
dword Dummy,Dummy ;Dummy ;FCBs
CmdLine byte 3,' A:',0dh
Dummy byte 20 dup (?)
SS_Save
and SP_Save
must be declared inside your
code segment. The other variables can be declared anywhere.
The exec
command automatically allocates memory for the program
being executed. If you haven't freed up unused memory before executing this
command, you may get an insufficient memory error. Therefore, you should
use the DOS deallocate memory command to free up unused memory before attempting
to use the exec
command.
If al
=1 when the exec
function executes, DOS will
load the specified file but will not execute it. This function is generally
used to load a program to execute into memory but give the caller control
and let the caller start that code. When this function call is made, es:bx
points at the following parameter block:
Offset Description
0 Word value containing the segment address of the environment block for the
new process. If you want to use the parent process' environment block set
this word to zero.
2 Dword pointer to the command tail for this operation. The command tail is the
command line string which will appear at location PSP:80.
6 Address of default FCB #1. For most programs, this should point at a block of
20 zeros (unless, of course, you're running a program which uses FCBs.).
0Ah Address of default FCB #2. Should also point at a block of 20 zeros.
0Eh SS:SP value. You must load these four bytes into SS and SP before starting
the application.
12h CS:IP value. These four bytes contain the starting address of the program.
The SSSP
and CSIP
fields are output values. DOS
fills in the fields and returns them in the load structure. The other fields
are all inputs which you must fill in before calling the exec
function
with al
=1.
When you execute the exec
command with al
=-3,
DOS simply loads an overlay into memory. Overlays generally consist of a
single code segment which contains some functions you want to execute. Since
you are not creating a new process, the parameter block for this type of
load is much simpler than for the other two types of load operations. On
entry, es:bx
must point at the following parameter block in
memory:
Offset Description
0 Word value containing the segment address of where this file is going
to be loaded into memory. The file will be loaded at offset zero within
this segment.
2 Word value containing a relocation factor for this file.
Unlike the load and execute functions, the overlay function does not automatically
allocate storage for the file being loaded. Your program has to allocate
sufficient storage and then pass the address of this storage block to the
exec
command (though the parameter block above). Only the segment
address of this block is passed to the exec
command, the offset
is always assumed to be zero. The relocation factor should also contain
the segment address for ".EXE" files. For ".COM" files,
the relocation factor parameter should be zero.
The overlay command is quite useful for loading overlays from disk into
memory. An overlay is a segment of code which resides on the disk drive
until the program actually needs to execute its code. Then the code is loaded
into memory and executed. Overlays can reduce the amount of memory your
program takes up by allowing you to reuse the same portion of memory for
different overlay procedures (clearly, only one such procedure can be active
at any one time). By placing seldom-used code and initialization code into
overlay files, you can help reduce the amount of memory used by your program
file. One word of caution, however, managing overlays is a very complex
task. This is not something a beginning assembly language programmer would
want to tackle right away. When loading a file into memory (as opposed to
loading and executing a file), DOS does not scramble all of the registers,
so you needn't take the extra care necessary to preserve the ss:sp
and other registers.
The MS-DOS Encyclopedia contains an excellent description of the use of
the exec
function.
[5] Actually, there are others. See the DOS
technical reference manual for more details. We will only consider these
three here.
[6] DOS also provides a call which
will return the PSP for your program.
- 13.3.6 - MS-DOS Memory Management Functions
- 13.3.6.1 - Allocate Memory
- 13.3.6.2 - Deallocate Memory
- 13.3.6.3 - Modify Memory Allocation
- 13.3.6.4 - Advanced Memory Management
Functions
- 13.3.7 - MS-DOS Process Control Functions
- 13.3.7.1 - Terminate Program Execution
- 13.3.7.2 - Terminate, but Stay Resident
- 13.3.7.3 - Execute a Program
Art of Assembly: Chapter Thirteen - 28 SEP 1996
[Chapter Thirteen][Previous]
[Next] [Art of
Assembly][Randall Hyde]